/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package novoservidor.codigo;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Richiely Batista
 */
public class Servidor {

    private int maxClientes;
    private int qtdClientes = 0;
    private int porta;
    private ServerSocket servidor;
    private String diretorio = System.getProperty("user.dir") + File.separator + "arquivos" + File.separator;// "C:/Users/Gean Delon/Documents/NetBeansProjects/Server/arquivos/";
    
    private DataOutputStream output;

    public Servidor(int pMaxClientes, int pPorta) {
        this.maxClientes = pMaxClientes;
        this.porta = pPorta;
        this.servidor = null;
    }

    public void iniciar() {
        try {
            servidor = new ServerSocket(this.porta);
            System.out.println("Servidor Iniciado. Aguardando conexao do(s) cliente(s)...");

            // Aguardando ConexÃµes dos Clientes
                    
            //while (true) {
                while (qtdClientes < maxClientes) {
                   Socket socket = servidor.accept();
                    output = new DataOutputStream(socket.getOutputStream());  // escrever dados no canal

                    // Envia mensagem  
                    output.writeUTF("Bem-vindo, voce esta conectado.");
                    
                    // Inicia a Thread do Servidor para tratar o cliente
                    new ThreadServidor(socket).start();
                    qtdClientes++;
                //}
            }

        } catch (IOException e) {
            System.out.println("Problemas na comunicaÃ§Ã£o: ");
            e.printStackTrace();
            System.exit(1);
        }
    }

    // Cada Thread cuidarÃ¡ das requisiÃ§Ãµes do cliente
    class ThreadServidor extends Thread {

        private Socket cliente;
        private DataInputStream input;
        private DataOutputStream output;

        public ThreadServidor(Socket pCliente) {
            this.cliente = pCliente;
        }

        @Override
        public void run() {

            try {
                this.input = new DataInputStream(this.cliente.getInputStream()); // receber dados do canal
                this.output = new DataOutputStream(this.cliente.getOutputStream());  // escrever dados no canal
            } catch (IOException ex) {
                Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
            }


            while (true) 
            {
                try {
                    String solicitacao = this.input.readUTF();

                    if (solicitacao != null) {

                        String[] valores = solicitacao.split(";");

                        if (valores[0].equals("PUT")) {
                            System.out.println("Chegou o PUT");
                            recebendoDoCliente();
                        } else if (valores[0].equals("GET")) {
                            System.out.println("Chegou o GET");
                            enviandoParaCliente(valores[1]);
                        } else if (valores[0].equals("SAIR")) {
                            System.out.println("Chegou o SAIR");
                            break;
                        }
                    }
                } catch (IOException e) {
                }
            }
            try {
                // o cliente enviou o comando SAIR
                // tentativa de fechamento do canal de comunicaÃ§Ã£o
                this.cliente.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void enviandoParaCliente(String pNomeDoArquivo) throws IOException {

            File arquivo = new File(diretorio + pNomeDoArquivo);

            if (arquivo.exists()) {
                System.out.println("Transferindo o arquivo: " + arquivo.getName());
                this.output.writeUTF(arquivo.getName());
                this.output.writeLong(arquivo.length());

                FileInputStream in = new FileInputStream(arquivo);
                OutputStream os = this.cliente.getOutputStream();

                int tamanho = 4096; // tamanho do buffer: 4KB
                byte[] buffer = new byte[tamanho];
                int lidos = -1;
                long tempo = System.currentTimeMillis();
                

                while ((lidos = in.read(buffer, 0, tamanho)) != -1) {
                    //System.out.println("Qtd. bytes enviados : " + lidos);
                    os.write(buffer, 0, lidos);
                }
                tempo = System.currentTimeMillis() - tempo;
                System.out.println( pNomeDoArquivo + " enviado com sucesso em: " + tempo / 1000f + " segundos");
                os.flush();
            } else {
                System.out.println("NÃ£o existe o arquivo!");
            }
        }

        private void recebendoDoCliente() throws IOException {

            String nomeArquivo = this.input.readUTF();

            if (nomeArquivo != null) {
                long size = this.input.readLong();
                System.out.println("Recebendo arquivo: " + nomeArquivo + " - " + size + " bytes.");

                // Verifica se tem a pasta de destino criada, caso nao tenha ele cria  
                File arquivo = new File(diretorio);
                if (arquivo.exists() == false) {
                    arquivo.mkdir();
                }

                FileOutputStream fos = new FileOutputStream(diretorio + nomeArquivo);
                InputStream in = this.cliente.getInputStream();

                int tamanho = 4096; // tamanho do buffer: 4KB
                byte[] buffer = new byte[tamanho];
                int lidos = -1;
                int tlidos = 0;
                long tempo = System.currentTimeMillis();

                while (tlidos < size) {
                    lidos = in.read(buffer, 0, tamanho);
                    fos.write(buffer, 0, lidos);
                    tlidos += lidos;
                }
                tempo = System.currentTimeMillis() - tempo;
                System.out.println( nomeArquivo + " recebido com sucesso em: " + tempo / 1000f + " segundos");
                fos.flush();
                
            }
        }
    }
}
